package com.hdu.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hdu.constant.RedisPrefixConst;
import com.hdu.dto.UserDetailDTO;
import com.hdu.dto.UserInfoDTO;
import com.hdu.dto.UserOnlineDTO;
import com.hdu.entity.Menu;
import com.hdu.entity.Teacher;
import com.hdu.entity.UserInfo;
import com.hdu.entity.UserRole;
import com.hdu.exception.BizException;
import com.hdu.mapper.RoleMapper;
import com.hdu.mapper.StudentMapper;
import com.hdu.mapper.TeacherMapper;
import com.hdu.mapper.UserInfoMapper;
import com.hdu.service.IMediaFileService;
import com.hdu.service.IUserInfoService;
import com.hdu.service.IUserRoleService;
import com.hdu.service.RedisService;
import com.hdu.util.PageUtils;
import com.hdu.util.UserUtils;
import com.hdu.vo.*;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户信息实体类 服务实现类
 * </p>
 *
 * @author xiaobai
 * @since 2024-05-21
 */
@Service
@RequiredArgsConstructor
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements IUserInfoService {

    private final UserInfoMapper userInfoMapper;

    private final TeacherMapper teacherMapper;

    private final StudentMapper studentMapper;

    private final RoleMapper roleMapper;

    private final IUserRoleService userRoleService;

    private final IMediaFileService mediaFileService;

    private final SessionRegistry sessionRegistry;

    private final RedisService redisService;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public UserInfoDTO getUserInfo() {
        String id = String.valueOf(UserUtils.getLoginUser().getUserInfoId());
        UserInfoDTO userInfoDTO = BeanUtil.copyProperties(userInfoMapper.selectById(id), UserInfoDTO.class);
        String username = String.valueOf(UserUtils.getLoginUser().getUsername());
        userInfoDTO.setUsername(username);
        userInfoDTO.setUserInfo(teacherMapper.selectById(username));
        userInfoDTO.setSoleInfo(studentMapper.selectById(username));
        QueryWrapper<Menu> wrapper = new QueryWrapper<>();
        wrapper.in("id", Arrays.asList(roleMapper.selectById(userInfoDTO.getRole()).getMenuList().split(", ")));

        userInfoDTO.setRoutes(new String[]{"User", "Category", "Discount", "ActivityEdit", "CouponRule", "Product", "Activity", "CouponAdd", "Trademark", "Attr", "ActivityAdd", "CouponEdit", "OrderShow", "Menu", "Spu", "UserList", "ClientUser", "Order", "Coupon", "Acl", "ActivityRule", "Role", "RoleAuth", "Refund", "OrderList", "Learn", "Class", "Case", "Student", "Message"});
        return userInfoDTO;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserInfo(UserInfoVO userInfoVO) {
        Teacher teacher = userInfoVO.getUserInfo();
        System.out.println(UserUtils.getLoginUser().toString());
        teacher.setId(UserUtils.getLoginUser().getUsername());
        teacherMapper.updateById(teacher);
        // 封装用户信息
        UserInfo userInfo = UserInfo.builder()
                .id(UserUtils.getLoginUser().getUserInfoId())
                .nickname(userInfoVO.getNickname())
                .avatar(userInfoVO.getAvatar())
                .build();
        userInfoMapper.updateById(userInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String updateUserAvatar(MultipartFile file, String tag) {
//        // 头像上传 oss
//        String avatar = uploadStrategyContext.executeUploadStrategy(file, FilePathEnum.AVATAR.getPath());
        // 头像上传 minio
        try {
            return "http://192.168.31.253:9090" + mediaFileService.uploadFile(file, "avatar/", file.getOriginalFilename(), tag).getUrl();
        } catch (IOException e) {
            throw new BizException("上传文件过程出错:" + e.getMessage());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveUserEmail(EmailVO emailVO) {
        if (!emailVO.getCode().equals(redisService.get(RedisPrefixConst.USER_CODE_KEY + emailVO.getEmail()).toString())) {
            throw new BizException("验证码错误！");
        }
        UserInfo userInfo = UserInfo.builder()
                .id(UserUtils.getLoginUser().getUserInfoId())
                .email(emailVO.getEmail())
                .build();
        userInfoMapper.updateById(userInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveUserPhone(PhoneVO phoneVO) {
        if (!phoneVO.getCode().equals(redisService.get(RedisPrefixConst.USER_CODE_KEY + phoneVO.getCode()).toString())) {
            throw new BizException("验证码错误！");
        }
        UserInfo userInfo = UserInfo.builder()
                .id(UserUtils.getLoginUser().getUserInfoId())
                .email(phoneVO.getPhone())
                .build();
        userInfoMapper.updateById(userInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserRole(UserRoleVO userRoleVO) {
        // 更新用户角色和昵称
        UserInfo userInfo = UserInfo.builder()
                .id(userRoleVO.getUserInfoId())
                .nickname(userRoleVO.getNickname())
                .build();
        userInfoMapper.updateById(userInfo);
        // 删除用户角色重新添加
        userRoleService.remove(new LambdaQueryWrapper<UserRole>()
                .eq(UserRole::getUserId, userRoleVO.getUserInfoId()));
        List<UserRole> userRoleList = userRoleVO.getRoleIdList().stream()
                .map(roleId -> UserRole.builder()
                        .roleId(roleId)
                        .userId(userRoleVO.getUserInfoId())
                        .build())
                .collect(Collectors.toList());
        userRoleService.saveBatch(userRoleList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserDisable(UserDisableVO userDisableVO) {
        // 更新用户禁用状态
        UserInfo userInfo = UserInfo.builder()
                .id(userDisableVO.getId())
                .isDisable(userDisableVO.getIsDisable())
                .build();
        userInfoMapper.updateById(userInfo);
    }

    @Override
    public PageResult<UserOnlineDTO> listOnlineUsers(ConditionVO conditionVO) {
        // 获取security在线session
        List<UserOnlineDTO> userOnlineDTOList = sessionRegistry.getAllPrincipals().stream()
                .filter(item -> sessionRegistry.getAllSessions(item, false).size() > 0)
                .map(item -> JSON.parseObject(JSON.toJSONString(item), UserOnlineDTO.class))
                .filter(item -> StringUtils.isBlank(conditionVO.getKeywords()) || item.getNickname().contains(conditionVO.getKeywords()))
                .sorted(Comparator.comparing(UserOnlineDTO::getLastLoginTime).reversed())
                .collect(Collectors.toList());
        // 执行分页
        int fromIndex = PageUtils.getLimitCurrent().intValue();
        int size = PageUtils.getSize().intValue();
        int toIndex = userOnlineDTOList.size() - fromIndex > size ? fromIndex + size : userOnlineDTOList.size();
        List<UserOnlineDTO> userOnlineList = userOnlineDTOList.subList(fromIndex, toIndex);
        return new PageResult<>(userOnlineList, userOnlineDTOList.size());
    }

    @Override
    public void removeOnlineUser(Integer userInfoId) {
        // 获取用户session
        List<Object> userInfoList = sessionRegistry.getAllPrincipals().stream().filter(item -> {
            UserDetailDTO userDetailDTO = (UserDetailDTO) item;
            return userDetailDTO.getUserInfoId().equals(userInfoId);
        }).collect(Collectors.toList());
        List<SessionInformation> allSessions = new ArrayList<>();
        userInfoList.forEach(item -> allSessions.addAll(sessionRegistry.getAllSessions(item, false)));
        // 注销session
        allSessions.forEach(SessionInformation::expireNow);
    }
}
